# vjoy_control.py
'''
    vJoy虚拟手柄控制DCS World - 模块级函数版本
    功能：通过vJoy虚拟手柄模拟飞行控制输入
    调用方式：from vjoy_control import *
'''

import time
import traceback

import pygetwindow as gw
import pyvjoy

# --------------------------
# 全局变量和常量定义
# --------------------------

# vJoy设备实例
_vjoy_device = pyvjoy.VJoyDevice(1)

# 轴参数定义 (vJoy轴范围：0x0000-0x8000)
AXIS_NEUTRAL = 0x4000  # 轴中立位置
AXIS_MAX = 0x8000  # 轴最大值
AXIS_MIN = 0x0000  # 轴最小值

# 油门当前位置 (0.0-1.0)
current_throttle = 0.5

# --------------------------
# 按钮定义（对应vJoy设备按钮编号）
# --------------------------
BUTTON_FLAPS = 1  # 襟翼打开/关闭按钮（主）
BUTTON_FLAPS_LAND = 2  # 着陆襟翼按钮
BUTTON_AIRBRAKE_EXTEND = 3  # 扰流板/减速板 打开
BUTTON_AIRBRAKE_RETRACT = 10  # 扰流板/减速板 关闭
BUTTON_GEAR_UP = 4  # 起落架收起按钮
BUTTON_GEAR_DOWN = 5  # 起落架放下按钮
BUTTON_WHEEL_BRAKE = 6  # 机轮刹车按钮
BUTTON_REVIVE = 7  # 飞机复活/重置按钮 在通用里设置
BUTTON_RUDDER_LEFT = 8  # 脚舵左微调按钮（备用）
BUTTON_RUDDER_RIGHT = 9  # 脚舵右微调按钮（备用）


# --------------------------
# 内部工具函数
# --------------------------

def _set_axis(axis, value):
    """设置轴位置的内部函数"""
    # 计算实际轴值（油门特殊处理）
    if axis == pyvjoy.HID_USAGE_Z:  # 油门轴
        axis_value = int(value * AXIS_MAX)
    else:  # 其他轴（俯仰/滚转/脚舵）
        axis_value = int(AXIS_NEUTRAL + value * (AXIS_MAX - AXIS_NEUTRAL))

    _vjoy_device.set_axis(axis, axis_value)


def _press_button(button_id, duration=0.1):
    """按下并释放按钮的内部函数"""
    _vjoy_device.set_button(button_id, 1)  # 按下按钮
    time.sleep(duration)
    _vjoy_device.set_button(button_id, 0)  # 释放按钮


# --------------------------
# 窗口控制函数
# --------------------------

def activate_dcs_window():
    """激活DCS游戏窗口"""
    dcs_window_title = "Digital Combat Simulator"
    windows = gw.getWindowsWithTitle(dcs_window_title)
    if not windows:
        print("[错误] 未找到DCS窗口！请确保游戏已启动")
        raise Exception(f"未找到窗口: {dcs_window_title}")

    dcs_window = windows[0]
    for _ in range(3):  # 最多尝试3次
        try:
            dcs_window.activate()
            time.sleep(2)  # 等待窗口激活
            if dcs_window.isActive:
                print("[状态] DCS窗口已激活")
                return True
        except Exception as e:
            print(f"[警告] 窗口激活失败: {e}")

    print("[错误] 无法激活DCS窗口")
    raise Exception("窗口激活失败")


# --------------------------
# 基础轴控制函数
# --------------------------

def set_pitch(value):
    """设置俯仰轴 (-1.0=拉杆/机头向上, 1.0=推杆/机头向下)"""
    _set_axis(pyvjoy.HID_USAGE_Y, value)
    print(f"[飞行控制] 俯仰 {'推杆' if value > 0 else '拉杆'} {abs(value) * 100:.0f}%")


def set_roll(value):
    """设置滚转轴 (-1.0=左压杆, 1.0=右压杆)"""
    _set_axis(pyvjoy.HID_USAGE_X, value)
    print(f"[飞行控制] 滚转 {'右' if value > 0 else '左'} {abs(value) * 100:.0f}%")


def set_throttle(value):
    """设置油门 (0.0=最小, 1.0=最大)"""
    global current_throttle
    current_throttle = max(0.0, min(1.0, value))  # 限制在0-1范围
    _set_axis(pyvjoy.HID_USAGE_Z, current_throttle)
    print(f"[引擎控制] 油门位置 {current_throttle * 100:.0f}%")


def set_rudder(value):
    """设置脚舵 (-1.0=左满舵, 1.0=右满舵)"""
    _set_axis(pyvjoy.HID_USAGE_RZ, value)
    print(f"[舵面控制] 方向舵 {'右' if value > 0 else '左'} {abs(value) * 100:.0f}%")


# --------------------------
# 复合控制指令（带中文输出）
# --------------------------

def pitch_up(duration=0.1):
    """机头向下（推杆）"""
    set_pitch(0.5)
    time.sleep(duration)
    set_pitch(0.0)
    print("[动作] 短时推杆 - 机头向下:",duration)


def pitch_down(duration=0.1):
    """机头向上（拉杆）"""
    set_pitch(-0.5)
    time.sleep(duration)
    set_pitch(0.0)
    print("[动作] 短时拉杆 - 机头向上:",duration)


def roll_left(duration=0.1):
    """向左滚转"""
    set_roll(-0.5)
    time.sleep(duration)
    set_roll(0.0)
    print("[动作] 短时左压杆 - 向左滚转:",duration)


def roll_right(duration=0.1):
    """向右滚转"""
    set_roll(0.5)
    time.sleep(duration)
    set_roll(0.0)
    print("[动作] 短时右压杆 - 向右滚转")


def throttle_up(duration=0.1):
    """增加油门"""
    global current_throttle
    new_throttle = min(1.0, current_throttle + 0.1)
    set_throttle(new_throttle)
    print("[引擎] 油门增加:",duration)


def throttle_down(duration=0.1):
    """减少油门"""
    global current_throttle
    new_throttle = max(0.0, current_throttle - 0.1)
    set_throttle(new_throttle)
    print("[引擎] 油门减少", duration)


def flaps_control(duration=0.1):
    """襟翼收放（起飞/巡航位置）"""
    _press_button(BUTTON_FLAPS, duration)
    print("[襟翼]切换 襟翼打开/关闭")


def flapsland_control(duration=0.1):
    """襟翼全放（着陆位置）"""
    _press_button(BUTTON_FLAPS_LAND, duration)
    print("[襟翼] 展开至着陆位置")


def airbrake_on_control(duration=0.1):
    """扰流板/减速板控制"""
    _press_button(BUTTON_AIRBRAKE_EXTEND, duration)
    print("[气动] 扰流板/减速板 打开")

def airbrake_off_control(duration=0.1):
    """扰流板/减速板控制"""
    _press_button(BUTTON_AIRBRAKE_RETRACT, duration)
    print("[气动] 扰流板/减速板 关闭")

def gearsoff_control(duration=0.1):
    """收起起落架"""
    _press_button(BUTTON_GEAR_UP, duration)
    print("[起落架] 收起")


def gearson_control(duration=0.1):
    """放下起落架"""
    _press_button(BUTTON_GEAR_DOWN, duration)
    print("[起落架] 放下")


def wheel_control(duration=0.1):
    """机轮刹车"""
    _press_button(BUTTON_WHEEL_BRAKE, duration)
    print("[刹车] 机轮刹车启动")


def foot_left(duration=0.1):
    """脚舵左转"""
    set_rudder(-1.0)
    time.sleep(duration)
    set_rudder(0.0)
    print("[舵面] 脚舵左转")


def foot_right(duration=0.1):
    """脚舵右转"""
    set_rudder(1.0)
    time.sleep(duration)
    set_rudder(0.0)
    print("[舵面] 脚舵右转")


def revive_control(duration=0.1):
    """飞机复活/重置"""
    _press_button(BUTTON_REVIVE, duration)
    print("[系统] 飞机重置/复活")


def heading_control(target_heading, current_heading):
    """自动航向调整"""
    error = target_heading - current_heading
    if error > 180:
        error -= 360
    elif error < -180:
        error += 360

    if abs(error) > 5:
        if error > 0:
            roll_right()
            print(f"[导航] 向右调整航向 {error:.1f}°")
        else:
            roll_left()
            print(f"[导航] 向左调整航向 {abs(error):.1f}°")


def reset():
    """重置所有控制输入"""
    _vjoy_device.reset()
    global current_throttle
    current_throttle = 0.5
    print("[系统] 所有控制重置")


# --------------------------
# 自测试函数
# --------------------------

def _test():
    print("\n=== vJoy控制器全功能测试 ===")
    try:
        activate_dcs_window()

        # 测试基础控制
        pitch_up(1)
        time.sleep(1)
        pitch_down(1)
        time.sleep(1)
        roll_left(0.2)
        time.sleep(1)
        roll_right(0.2)
        time.sleep(1)
        throttle_up(1)
        time.sleep(1)
        throttle_down(1)
        time.sleep(1)
        set_rudder(0.5)
        time.sleep(3)

        # 测试复合功能
        flaps_control()
        time.sleep(1)
        gearson_control()
        time.sleep(1)
        gearsoff_control()
        time.sleep(1)
        airbrake_on_control()
        time.sleep(1)
        airbrake_off_control()
        time.sleep(1)
        foot_left()
        time.sleep(1)
        revive_control()
        time.sleep(1)

        print("=== 所有测试执行完成 ===")
    except Exception as e:
        print(f"!!! 测试失败: {e}")
    finally:
        reset()


if __name__ == "__main__":
    _test()